#ifndef _GRO_PAINTER_H__
#define _GRO_PAINTER_H__

//#include "GRO_Gui.h"

#include "SDL.h"
#include "GRO_Renderer.h"
#include <string>
#include <list>

namespace GRO
{
    
    enum DirectionEnum
    {
        UP,
        DOWN,
        LEFT,
        RIGHT
    };
    
    
    class Rect
    {
    public:
        int up, down, left, right;

        Rect()
                : up(0)
                , down(0)
                , left(0)
                , right(0)
        {}
        Rect(int Up, int Down, int Left, int Right)
                : up(Up)
                , down(Down)
                , left(Left)
                , right(Right)
        {}
        
        std::string toString() const
        {
            char buf[30];
            snprintf(buf, 30, "[%d, %d, %d, %d]", up, down, left, right);
            return buf;
        }
    };
    
    class GradientPoint
    {
        public:
        float pos;
        Uint32 color;
        Uint8 alpha;
        
        GradientPoint()
        : pos(0.5f)
        , color(0x000000)
        , alpha(SDL_ALPHA_OPAQUE)
        {}
        GradientPoint(float Pos, Uint32 Color, Uint8 Alpha = SDL_ALPHA_OPAQUE)
        : pos(Pos)
        , color(Color)
        , alpha(Alpha)
        {}
    };
    
    inline bool compare_GradientPoint(const GradientPoint& first, const GradientPoint& second)
    {
        return first.pos <= second.pos;
    }

    
    class GradientRamp
    {
        public:
        bool deleteMe;
        std::list<GradientPoint> controls;
        GradientPoint first;
        GradientPoint last;
        
        GradientRamp()
        : deleteMe(true)
        , first(0, 0xFFFFFF)
        , last(1, 0x000000)
        {}
        GradientRamp(Uint32 FirstColor, Uint32 LastColor)
        : deleteMe(true)
        , first(0, FirstColor)
        , last(1, LastColor)
        {}
        GradientRamp(Uint32 FirstColor, Uint8 FirstAlpha, Uint32 LastColor, Uint8 LastAlpha)
        : deleteMe(true)
        , first(0, FirstColor, FirstAlpha)
        , last(1, LastColor, LastAlpha)
        {}
        GradientRamp(Uint16 numColors, Uint32 FirstColor, Uint32 SecondColor, float SecondPos, Uint32 ThirdColor, ...);
        
        
        void set(Uint16 numColors, Uint32 FirstColor, Uint32 SecondColor, float SecondPos, Uint32 ThirdColor, ...);

        void setAlpha(Uint16 numColors, Uint32 FirstColor, Uint8 FirstAlpha, Uint32 SecondColor, Uint8 SecondAlpha, float SecondPos, Uint32 ThirdColor, Uint8 ThirdAlpha, ...);
        
        void add(const GradientPoint& control)
        {
            controls.push_back(control);
            controls.sort(compare_GradientPoint);
        }
        
        void remove(int index);
        
        void remove(float from, float to);
        
        void reverse();
        
        void sort()
        {
            controls.sort(compare_GradientPoint);
        }
        
        
    };


// Abstract base class (interface) for all painters
    class Painter
    {
    public:
        Painter()
        {}
        virtual void draw(const SDL_Rect& rect, Renderer* renderer) = 0;
        virtual Painter* clone() = 0;
    };

// Base class for Background painters
// Standard background painting: drop shadow and flat color
    class BoxPainter : public Painter
    {
    
    protected:
        // FIXME: This should probably use the renderer somehow
        void pushClipRect(Sint16 x, Sint16 y);
    public:
        int dropShadowX;
        int dropShadowY;
        Uint32 dropShadowColor;
        Uint8 dropShadowAlpha;
        bool clip;

        Uint32 boxColor;
        Uint8 boxAlpha;

        BoxPainter()
                : dropShadowX(0)
                , dropShadowY(0)
                , dropShadowColor(0x000000)
                , dropShadowAlpha(127)
                , clip(0)
                , boxColor(0x777777)
                , boxAlpha(SDL_ALPHA_OPAQUE)
        {}
        BoxPainter(Uint32 BoxColor, int DropShadowX = 0, int DropShadowY = 0)
                : dropShadowX(DropShadowX)
                , dropShadowY(DropShadowY)
                , dropShadowColor(0x000000)
                , dropShadowAlpha(127)
                , clip(0)
                , boxColor(BoxColor)
                , boxAlpha(SDL_ALPHA_OPAQUE)
        {}
        // This is better than the copy constructor because I don't need to know the final type first.
        // I'm putting it here, rather than in Painter because Box and Frame painters might never be
        // mixed in such a way that requires copies and I can avoid a cast.
        virtual BoxPainter* clone()
        {
            return new BoxPainter(*this);
        }

        virtual void drawDropShadow(const SDL_Rect& rect, Renderer* renderer);

        virtual void drawBoxColor(const SDL_Rect& rect, Renderer* renderer)
        {
            if(renderer == NULL)
                return;
            if (boxAlpha != SDL_ALPHA_TRANSPARENT && rect.w > 0 && rect.h > 0)
            {
                if (boxAlpha == SDL_ALPHA_OPAQUE)
                    renderer->RectFilled(rect.x, rect.y, rect.x + rect.w - 1, rect.y + rect.h - 1, boxColor);
                else
                    renderer->RectFilledBlend(rect.x, rect.y, rect.x + rect.w - 1, rect.y + rect.h - 1, boxColor, boxAlpha);
            }
        }

        virtual void draw(const SDL_Rect& rect, Renderer* renderer)
        {
            if(renderer == NULL)
                return;
            drawDropShadow(rect, renderer);
            drawBoxColor(rect, renderer);
        }
    };
    
    
// ******************************
// ******** FramePainter ********
// ******************************


// Base class for Frame painters
// Standard frame painting: border
    class FramePainter : public Painter
    {
    public:
        Uint16 borderThickness;
        Uint32 borderColor;
        Uint8 borderAlpha;

        FramePainter()
                : borderThickness(1)
                , borderColor(0x000000)
                , borderAlpha(SDL_ALPHA_OPAQUE)
        {}
        FramePainter(Uint16 BorderThickness, Uint32 BorderColor = 0x000000, Uint32 BorderAlpha = SDL_ALPHA_OPAQUE)
                : borderThickness(BorderThickness)
                , borderColor(BorderColor)
                , borderAlpha(BorderAlpha)
        {}
        // This is better than the copy constructor because I don't need to know the final type first.
        virtual FramePainter* clone()
        {
            return new FramePainter(*this);
        }

        virtual void drawBorder(const SDL_Rect& rect, Renderer* renderer)
        {
            if(renderer == NULL)
                return;
            if (borderThickness > 0 && borderAlpha != SDL_ALPHA_TRANSPARENT && rect.w > 0 && rect.h > 0)
            {
                if (borderAlpha == SDL_ALPHA_OPAQUE)
                    for (int i = 0; i < borderThickness; i++)
                        renderer->Rect(rect.x + i, rect.y + i, rect.x + rect.w - 1 - i, rect.y + rect.h - 1 - i, borderColor);
                else
                    for (int i = 0; i < borderThickness; i++)
                        renderer->RectBlend(rect.x + i, rect.y + i, rect.x + rect.w - 1 - i, rect.y + rect.h - 1 - i, borderColor, borderAlpha);
            }
        }

        virtual void draw(const SDL_Rect& rect, Renderer* renderer)
        {
            if(renderer == NULL)
                return;
            drawBorder(rect, renderer);
        }
    };

    
    // Base class for design painters
    // Inherit from this class to draw custom icons and such on widgets
    class DesignPainter : public Painter
    {
    public:
        Uint32 color;
        Uint8 alpha;
        Uint16 thickness;
        
        DesignPainter()
                : color(0x000000)
                , alpha(SDL_ALPHA_OPAQUE)
                , thickness(1)
        {}
        DesignPainter(Uint16 Thickness, Uint32 Color, Uint8 Alpha = SDL_ALPHA_OPAQUE)
                : color(Color)
                , alpha(Alpha)
                , thickness(Thickness)
        {}
        
        virtual void draw(const SDL_Rect& rect, Renderer* renderer)
        {
            if(renderer == NULL)
                return;
            drawDesign(rect, NULL, renderer);
        }
        virtual void drawDesign(const SDL_Rect& rect, Rect* push, Renderer* renderer) = 0;
        virtual DesignPainter* clone() = 0;
    };
    
    
    // Painters for the default theme
    
    #ifndef GRO_NO_DEFAULT_PAINTERS
    
    // Box Painters
    
    class RoundedBoxPainter : public BoxPainter
    {
    public:
        float radius;

        RoundedBoxPainter()
                : BoxPainter()
                , radius(10)
        {}
        RoundedBoxPainter(Uint32 BoxColor, float Radius)
                : BoxPainter()
                , radius(Radius)
        {
            boxColor = BoxColor;
        }
        
        virtual BoxPainter* clone()
        {
            return new RoundedBoxPainter(*this);
        }

        virtual void drawBoxColor(const SDL_Rect& rect, Renderer* renderer)
        {
            if(renderer == NULL)
                return;
            if (boxAlpha != SDL_ALPHA_TRANSPARENT && rect.w > 0 && rect.h > 0)
            {
                renderer->RectRoundFilledBlend(rect.x, rect.y, rect.x + rect.w - 1, rect.y + rect.h - 1, radius, boxColor, boxAlpha);
            }
        }

        virtual void draw(const SDL_Rect& rect, Renderer* renderer)
        {
            if(renderer == NULL)
                return;
            drawDropShadow(rect, renderer);
            drawBoxColor(rect, renderer);
        }
    };
    


    // Frame Painters
    
    class BevelFramePainter : public FramePainter
    {
    public:
        int thickness;
        bool invert;
        Uint32 highlightColor;
        Uint8 highlightAlpha;
        Uint32 shadowColor;
        Uint8 shadowAlpha;

        BevelFramePainter()
                : FramePainter()
                , thickness(2)
                , invert(0)
                , highlightColor(0xffffff)
                , highlightAlpha(SDL_ALPHA_OPAQUE)
                , shadowColor(0x000000)
                , shadowAlpha(SDL_ALPHA_OPAQUE)
        {}
        BevelFramePainter(int Thickness, int BorderThickness, bool Invert)
                : FramePainter(BorderThickness)
                , thickness(Thickness)
                , invert(Invert)
                , highlightColor(0xffffff)
                , highlightAlpha(SDL_ALPHA_OPAQUE)
                , shadowColor(0x000000)
                , shadowAlpha(SDL_ALPHA_OPAQUE)
        {}
        virtual FramePainter* clone()
        {
            return new BevelFramePainter(*this);
        }

        // Draws bevelled edge on the given side of a rectangle.  Preference is on top-left for overlapping pixels.
        virtual void drawEdge(const SDL_Rect& rect, DirectionEnum direction, Uint32 color, Uint8 alpha, Renderer* renderer)
        {
            if(renderer == NULL)
                return;
            if (alpha != SDL_ALPHA_TRANSPARENT && rect.w > 0 && rect.h > 0)
            {
                if (alpha == SDL_ALPHA_OPAQUE)
                {
                    if (direction == UP)
                        for (int i = 0; i < thickness; i++)
                            renderer->LineH(rect.x + i, rect.y + i, rect.x + rect.w - 1 - i, color);
                    else if (direction == DOWN)
                        for (int i = 0; i < thickness; i++)
                            renderer->LineH(rect.x + i + 1, rect.y + rect.h - 1 - i, rect.x + rect.w - 1 - i - 1, color);
                    else if (direction == LEFT)
                        for (int i = 0; i < thickness; i++)
                            renderer->LineV(rect.x + i, rect.y + i + 1, rect.y + rect.h - 1 - i, color);
                    else if (direction == RIGHT)
                        for (int i = 0; i < thickness; i++)
                            renderer->LineV(rect.x + rect.w - 1 - i, rect.y + i + 1, rect.y + rect.h - 1 - i, color);
                }
                else
                {
                    if (direction == UP)
                        for (int i = 0; i < thickness; i++)
                            renderer->LineHBlend(rect.x + i, rect.y + i, rect.x + rect.w - 1 - i, color, alpha);
                    else if (direction == DOWN)
                        for (int i = 0; i < thickness; i++)
                            renderer->LineHBlend(rect.x + i + 1, rect.y + rect.h - 1 - i, rect.x + rect.w - 1 - i - 1, color, alpha);
                    else if (direction == LEFT)
                        for (int i = 0; i < thickness; i++)
                            renderer->LineVBlend(rect.x + i, rect.y + i + 1, rect.y + rect.h - 1 - i, color, alpha);
                    else if (direction == RIGHT)
                        for (int i = 0; i < thickness; i++)
                            renderer->LineVBlend(rect.x + rect.w - 1 - i, rect.y + i + 1, rect.y + rect.h - 1 - i, color, alpha);
                }
            }
        }

        virtual void draw(const SDL_Rect& rect, Renderer* renderer)
        {
            if(renderer == NULL)
                return;
            if (invert)
            {
                drawEdge(rect, DOWN, highlightColor, highlightAlpha, renderer);
                drawEdge(rect, RIGHT, highlightColor, highlightAlpha, renderer);
                drawEdge(rect, UP, shadowColor, shadowAlpha, renderer);
                drawEdge(rect, LEFT, shadowColor, shadowAlpha, renderer);
            }
            else
            {
                drawEdge(rect, DOWN, shadowColor, shadowAlpha, renderer);
                drawEdge(rect, RIGHT, shadowColor, shadowAlpha, renderer);
                drawEdge(rect, UP, highlightColor, highlightAlpha, renderer);
                drawEdge(rect, LEFT, highlightColor, highlightAlpha, renderer);
            }
            drawBorder(rect, renderer);
        }
    };
    
    

    
    class RoundedFramePainter : public FramePainter
    {
    public:
        int thickness;
        bool invert;
        Uint32 highlightColor;
        Uint8 highlightAlpha;
        Uint32 shadowColor;
        Uint8 shadowAlpha;
        float radius;

        RoundedFramePainter()
                : FramePainter()
                , thickness(2)
                , invert(0)
                , highlightColor(0xffffff)
                , highlightAlpha(SDL_ALPHA_OPAQUE)
                , shadowColor(0x000000)
                , shadowAlpha(SDL_ALPHA_OPAQUE)
                , radius(10)
        {}
        RoundedFramePainter(int Thickness, int BorderThickness, float Radius, bool Invert)
                : FramePainter(BorderThickness)
                , thickness(Thickness)
                , invert(Invert)
                , highlightColor(0xffffff)
                , highlightAlpha(SDL_ALPHA_OPAQUE)
                , shadowColor(0x000000)
                , shadowAlpha(SDL_ALPHA_OPAQUE)
                , radius(Radius)
        {}
        virtual FramePainter* clone()
        {
            return new RoundedFramePainter(*this);
        }

        virtual void draw(const SDL_Rect& rect, Renderer* renderer)
        {
            if(renderer == NULL)
                return;
            if (invert)
            {
                renderer->LineHBlend(rect.x + radius, rect.y, rect.x + rect.w - radius - 1, shadowColor, shadowAlpha);
                renderer->LineVBlend(rect.x, rect.y + radius, rect.y + rect.h - radius - 1, shadowColor, shadowAlpha);
                renderer->LineVBlend(rect.x + rect.w - 1, rect.y + radius, rect.y + rect.h - radius - 1, highlightColor, highlightAlpha);
                renderer->LineHBlend(rect.x + radius, rect.y + rect.h - 1, rect.x + rect.w - radius - 1, highlightColor, highlightAlpha);
                
                renderer->ArcBlend(rect.x + radius, rect.y + radius, radius, 180, 270, shadowColor, shadowAlpha);
                renderer->ArcBlend(rect.x + rect.w - radius - 1, rect.y + radius, radius, 270, 315, shadowColor, shadowAlpha);
                renderer->ArcBlend(rect.x + rect.w - radius - 1, rect.y + radius, radius, 315, 360, highlightColor, highlightAlpha);
                renderer->ArcBlend(rect.x + radius, rect.y + rect.h - radius - 1, radius, 135, 180, shadowColor, shadowAlpha);
                renderer->ArcBlend(rect.x + radius, rect.y + rect.h - radius - 1, radius, 90, 135, highlightColor, highlightAlpha);
                renderer->ArcBlend(rect.x + rect.w - radius - 1, rect.y + rect.h - radius - 1, radius, 0, 90, highlightColor, highlightAlpha);
            }
            else
            {
                renderer->LineHBlend(rect.x + radius, rect.y, rect.x + rect.w - radius - 1, highlightColor, highlightAlpha);
                renderer->LineVBlend(rect.x, rect.y + radius, rect.y + rect.h - radius - 1, highlightColor, highlightAlpha);
                renderer->LineVBlend(rect.x + rect.w - 1, rect.y + radius, rect.y + rect.h - radius - 1, shadowColor, shadowAlpha);
                renderer->LineHBlend(rect.x + radius, rect.y + rect.h - 1, rect.x + rect.w - radius - 1, shadowColor, shadowAlpha);
                
                renderer->ArcBlend(rect.x + radius, rect.y + radius, radius, 180, 270, highlightColor, highlightAlpha);
                renderer->ArcBlend(rect.x + rect.w - radius - 1, rect.y + radius, radius, 270, 315, highlightColor, highlightAlpha);
                renderer->ArcBlend(rect.x + rect.w - radius - 1, rect.y + radius, radius, 315, 360, shadowColor, shadowAlpha);
                renderer->ArcBlend(rect.x + radius, rect.y + rect.h - radius - 1, radius, 135, 180, highlightColor, highlightAlpha);
                renderer->ArcBlend(rect.x + radius, rect.y + rect.h - radius - 1, radius, 90, 135, shadowColor, shadowAlpha);
                renderer->ArcBlend(rect.x + rect.w - radius - 1, rect.y + rect.h - radius - 1, radius, 0, 90, shadowColor, shadowAlpha);
            }
            //drawBorder(rect);
        }
    };
    

    // Design Painters
    
    
    class CheckDesignPainter : public DesignPainter
    {
    public:

        CheckDesignPainter()
                : DesignPainter()
        {}
        CheckDesignPainter(Uint16 Thickness, Uint32 Color, Uint8 Alpha = SDL_ALPHA_OPAQUE)
                : DesignPainter(Thickness, Color, Alpha)
        {}
        
        virtual DesignPainter* clone()
        {
            return new CheckDesignPainter(*this);
        }

        virtual void drawDesign(const SDL_Rect& rect, Rect* push, Renderer* renderer)
        {
            if(renderer == NULL)
                return;
            Sint16 x = rect.x;
            Sint16 y = rect.y;
            Sint16 x2 = rect.x + rect.w - 1;
            Sint16 y2 = rect.y + rect.h - 1;
            if(push != NULL)
            {
                x += push->left;
                x2 -= push->right;
                y += push->up;
                y2 -= push->down;
            }
            
            // switch thickness...
            
            renderer->LineBlendAA(x, y + (y2 - y)/2, x + (x2 - x)/3, y2, color, alpha);
            renderer->LineBlendAA(x + (x2 - x)/3 + 1, y2, x2, y, color, alpha);
        }
    };

    class ArrowheadDesignPainter : public DesignPainter
    {
    public:
        DirectionEnum direction;
    
        ArrowheadDesignPainter()
                : DesignPainter()
                , direction(UP)
        {}
        ArrowheadDesignPainter(Uint16 Thickness, Uint32 Color, Uint8 Alpha = SDL_ALPHA_OPAQUE)
                : DesignPainter(Thickness, Color, Alpha)
                , direction(UP)
        {}
        ArrowheadDesignPainter(DirectionEnum Direction, Uint16 Thickness, Uint32 Color, Uint8 Alpha = SDL_ALPHA_OPAQUE)
                : DesignPainter(Thickness, Color, Alpha)
                , direction(Direction)
        {}
        
        virtual DesignPainter* clone()
        {
            return new ArrowheadDesignPainter(*this);
        }

        virtual void drawDesign(const SDL_Rect& rect, Rect* push, Renderer* renderer)
        {
            if(renderer == NULL)
                return;
            Sint16 x = rect.x;
            Sint16 y = rect.y;
            Sint16 x2 = rect.x + rect.w - 1;
            Sint16 y2 = rect.y + rect.h - 1;
            if(push != NULL)
            {
                x += push->left;
                x2 -= push->right;
                y += push->up;
                y2 -= push->down;
            }
            
            int halfX = 0;
            int halfY = 0;
            halfX = (x + x2)/2 - x;  // FIXME!!  Use these vars to make the arrows more symmetric.
            halfY = (y + y2)/2 - y;
            switch(direction)
            {
                case UP:
                //renderer->LineBlend(x, y + Sint16((y2 - y)*2/3.0f), (x + x2)/2, y, color, alpha);
                //renderer->LineBlend((x + x2)/2 + 1, y, x2, y + Sint16((y2 - y)*2/3.0f), color, alpha);
                // AA + Thickness interferes with blending?
                for(int i = 1, j = 1; i < thickness; i+=2, j++)
                {
                    renderer->LineBlendAA(x, y + Sint16((y2 - y)*2/3.0f) + j, x + halfX, y + j, color, alpha);
                    renderer->LineBlendAA(x + halfX, y + j, x + 2*halfX, y + Sint16((y2 - y)*2/3.0f) + j, color, alpha);
                }
                for(int i = 0, j = 0; i < thickness; i+=2, j++)
                {
                    renderer->LineBlendAA(x, y + Sint16((y2 - y)*2/3.0f) - j, x + halfX, y - j, color, alpha);
                    renderer->LineBlendAA(x + halfX, y - j, x + 2*halfX, y + Sint16((y2 - y)*2/3.0f) - j, color, alpha);
                }
                break;
                case DOWN:
                //renderer->LineBlend(x, y2 - Sint16((y2 - y)*2/3.0f), (x + x2)/2, y2, color, alpha);
                //renderer->LineBlend((x + x2)/2 + 1, y2, x2, y2 - Sint16((y2 - y)*2/3.0f), color, alpha);
                for(int i = 1, j = 1; i < thickness; i+=2, j++)
                {
                    renderer->LineBlendAA(x, y2 - Sint16((y2 - y)*2/3.0f) + j, x + halfX, y2 + j, color, alpha);
                    renderer->LineBlendAA(x + halfX + 1, y2 + j, x + 2*halfX + 1, y2 - Sint16((y2 - y)*2/3.0f) + j, color, alpha);
                }
                for(int i = 0, j = 0; i < thickness; i+=2, j++)
                {
                    renderer->LineBlendAA(x, y2 - Sint16((y2 - y)*2/3.0f) - j, x + halfX, y2 - j, color, alpha);
                    renderer->LineBlendAA(x + halfX + 1, y2 - j, x + 2*halfX + 1, y2 - Sint16((y2 - y)*2/3.0f) - j, color, alpha);
                }
                break;
                case LEFT:
                for(int i = 1, j = 1; i < thickness; i+=2, j++)
                {
                    //renderer->LineBlendAA(x, y + Sint16((y2 - y)*2/3.0f) + j, x + halfX, y + j, color, alpha);
                    //renderer->LineBlendAA(x + halfX, y + j, x + 2*halfX, y + Sint16((y2 - y)*2/3.0f) + j, color, alpha);
                    renderer->LineBlendAA(x + Sint16((x2 - x)*2/3.0f) + j, y,  x + j, y + halfY, color, alpha);
                    renderer->LineBlendAA(x + j, y + halfY, x + Sint16((x2 - x)*2/3.0f) + j, y + 2*halfY, color, alpha);
                }
                for(int i = 0, j = 0; i < thickness; i+=2, j++)
                {
                    //renderer->LineBlendAA(x, y + Sint16((y2 - y)*2/3.0f) - j, x + halfX, y - j, color, alpha);
                    //renderer->LineBlendAA(x + halfX, y - j, x + 2*halfX, y + Sint16((y2 - y)*2/3.0f) - j, color, alpha);
                    renderer->LineBlendAA(x + Sint16((x2 - x)*2/3.0f) - j, y, x - j, y + halfY, color, alpha);
                    renderer->LineBlendAA(x - j, y + halfY, x + Sint16((x2 - x)*2/3.0f) - j, y + 2*halfY, color, alpha);
                }
                break;
                case RIGHT:
                for(int i = 1, j = 1; i < thickness; i+=2, j++)
                {
                    renderer->LineBlendAA(x2 - Sint16((x2 - x)*2/3.0f) + j, y, x2 + j, y + halfY, color, alpha);
                    renderer->LineBlendAA(x2 + j, y + halfY, x2 - Sint16((x2 - x)*2/3.0f) + j, y + 2*halfY, color, alpha);
                }
                for(int i = 0, j = 0; i < thickness; i+=2, j++)
                {
                    renderer->LineBlendAA(x2 - Sint16((x2 - x)*2/3.0f) - j, y, x2 - j - 1, y + halfY, color, alpha);
                    renderer->LineBlendAA(x2 - j, y + halfY, x2 - Sint16((x2 - x)*2/3.0f) - j, y + 2*halfY, color, alpha);
                }
                break;
            }
        }
    };
    
    #endif  //GRO_NO_DEFAULT_PAINTERS
    
    
    
    struct GRO_BoxPainterID
    {
        private:
        unsigned int id;
        
        public:
        
        GRO_BoxPainterID()
            : id(0)
        {}
        
        GRO_BoxPainterID(unsigned int id)
            : id(id)
        {}
        
        void setValue(unsigned int id)
        {
            this->id = id;
        }
        
        unsigned int getValue() const
        {
            return id;
        }
        
        bool operator<(const GRO_BoxPainterID& painterID) const
        {
            return (id < painterID.id);
        }
        
        bool operator==(const GRO_BoxPainterID& painterID) const
        {
            return (id == painterID.id);
        }
        
        void draw(const SDL_Rect& rect, Renderer* renderer);
    };
    
    struct GRO_FramePainterID
    {
        private:
        unsigned int id;
        
        public:
        
        GRO_FramePainterID()
            : id(0)
        {}
        
        GRO_FramePainterID(unsigned int id)
            : id(id)
        {}
        
        void setValue(unsigned int id)
        {
            this->id = id;
        }
        
        unsigned int getValue() const
        {
            return id;
        }
        
        bool operator<(const GRO_FramePainterID& painterID) const
        {
            return (id < painterID.id);
        }
        
        bool operator==(const GRO_FramePainterID& painterID) const
        {
            return (id == painterID.id);
        }
        
        void draw(const SDL_Rect& rect, Renderer* renderer);
    };
    
    struct GRO_DesignPainterID
    {
        private:
        unsigned int id;
        
        public:
        
        GRO_DesignPainterID()
            : id(0)
        {}
        
        GRO_DesignPainterID(unsigned int id)
            : id(id)
        {}
        
        void setValue(unsigned int id)
        {
            this->id = id;
        }
        
        unsigned int getValue() const
        {
            return id;
        }
        
        bool operator<(const GRO_DesignPainterID& painterID) const
        {
            return (id < painterID.id);
        }
        
        bool operator==(const GRO_DesignPainterID& painterID) const
        {
            return (id == painterID.id);
        }
        
        void drawDesign(const SDL_Rect& rect, Rect* designPush, Renderer* renderer);
    };
    
    
    
    
    class PainterSet
    {
        public:
        GRO_BoxPainterID box;
        GRO_FramePainterID frame;
        GRO_DesignPainterID design;
        
        PainterSet()
        {}
        ~PainterSet()
        {}
        
    };
    
    
    class PainterMap
    {
        private:
        
        public:
        GRO_BoxPainterID Default_DarkShadowBoxPainter;
        GRO_BoxPainterID Default_DarkBoxPainter;
        GRO_BoxPainterID Default_LightBoxPainter;
        
        GRO_FramePainterID Default_ButtonUpPainter;
        GRO_FramePainterID Default_ButtonDownPainter;
        GRO_FramePainterID Default_GroupPainter;

        GRO_DesignPainterID Default_CheckDesignPainter;
        GRO_DesignPainterID Default_UpArrowDesignPainter;
        GRO_DesignPainterID Default_DownArrowDesignPainter;
        
        
        
        std::map<GRO_BoxPainterID, BoxPainter*> boxPainters;
        std::map<GRO_FramePainterID, FramePainter*> framePainters;
        std::map<GRO_DesignPainterID, DesignPainter*> designPainters;
        
        PainterMap();
        ~PainterMap();
        
        GRO_BoxPainterID add(BoxPainter* painter);
        GRO_FramePainterID add(FramePainter* painter);
        GRO_DesignPainterID add(DesignPainter* painter);
        
        BoxPainter* get(const GRO_BoxPainterID& id);
        FramePainter* get(const GRO_FramePainterID& id);
        DesignPainter* get(const GRO_DesignPainterID& id);
        
        BoxPainter* remove(const GRO_BoxPainterID& id);
        FramePainter* remove(const GRO_FramePainterID& id);
        DesignPainter* remove(const GRO_DesignPainterID& id);
    };



    
    PainterMap* getPainterMap();
    void setPainterMap(PainterMap* painterMap);


}

#endif
